﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Ndo.Maths
{
    public class ST
    {
        public ST()
        {
            reset();
        }
        private bool dirty;
        private double min, max, sum, mean, std, sd, d;
        private List<double> data = new List<double>();
        private void reset()
        {
            min = double.NaN;
            max = double.NaN;
            mean = double.NaN;
            sum = double.NaN;
            std = double.NaN;
            sd = double.NaN;
            d = double.NaN;
            dirty = false;
        }
        public void Reset()
        {
            data.Clear();
            reset();
        }
        public void Add(double v)
        {
            dirty = true;
            data.Add(v);
        }
        public void Add(IEnumerable<double> a)
        {
            dirty = true;
            foreach (double d1 in a)
            {
                data.Add(d1);
            }
        }
        public double StandardDeviation { get { calc(); return std; } }
        public double SquareDeviation { get { calc(); return sd; } }
        public double Deviation { get { calc(); return d; } }
        public double Min { get { calc(); return min; } }
        public double Max { get { calc(); return max; } }
        public double Mean { get { calc(); return mean; } }
        public double Sum { get { calc(); return sum;} }
        public int Count { get { return data.Count; } }

        private void calc()
        {
            if(!dirty)
                return;
            dirty = false;
            reset();
            if (data.Count == 0)
                return;
            foreach (double d1 in data)
            {
                if(double.IsNaN(min) || min>d1)
                    min = d1;
                if(double.IsNaN(max) || max<d1)
                    max = d1;
                if(double.IsNaN(sum))
                    sum = d1;
                else
                    sum += d1;
            }
            mean = sum/data.Count;
            if(double.IsNaN(mean))
                return;
            double s = 0;
            foreach (double d1 in data)
            {
                double d2 = d1 - mean;
                s += d2*d2;
            }
            if(data.Count>1)
                std = Math.Sqrt(s/(data.Count - 1));
            sd = s/data.Count;
            d = Math.Sqrt(sd);
        }

        public override string ToString()
        {
            calc();
            return string.Format("min:{0}\tmax:{1}\tmean:{2}\td:{3}\tcount:{4}", min, max, mean, d, data.Count);
        }
    }
}
